﻿// Copyright (c) 2007-2021 西安交通信息投资营运有限公司 版权所有
// 作者:吕艳阳

using DevExpress.Data;
using DevExpress.Utils;
using DevExpress.Utils.Design;
using DevExpress.Utils.Drawing;
using DevExpress.Utils.Menu;
using DevExpress.Utils.Serializing;
using DevExpress.XtraBars;
using DevExpress.XtraTreeList;
using DevExpress.XtraTreeList.Columns;
using DevExpress.XtraTreeList.Nodes;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using DevExpress.XtraEditors;
using DevExpress.XtraEditors.Controls;
using XCI.Core;
using XCI.Extensions;
using XCI.Setting;
using XCI.Helper;

namespace XCI.Windows
{
    /// <summary>
    /// 扩展的树形控件
    /// </summary>
    [System.ComponentModel.DesignerCategory("Code")]
    public class TreeListPlus : DevExpress.XtraTreeList.TreeList, ISettingSerializer
    {
        private readonly Stopwatch sw = new Stopwatch();
        private TreeListNode dragNode;
        private bool isDataLoading;
        private Type _modelType;
        private ApiModel _apiModelInfo;
        private object _focusNodeId;
        private List<object> _expandNodeIds;
        private List<object> _checkedNodeIds;
        private int currentMaxRecordLength;

        public TreeListPlus()
        {
            //if (WinFormHelper.IsDesignMode())
            //{
            //    BorderStyle = DevExpress.XtraEditors.Controls.BorderStyles.NoBorder;
            //    OptionsBehavior.Editable = false;
            //}
        }

        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public SettingStoreManager SettingManager { get; set; }

        /// <summary>
        /// 配置标识
        /// </summary>
        [Category("XCI"), Description("配置标识")]
        [SmartTagProperty("配置标识", "XCI", SmartTagActionType.RefreshAfterExecute)]
        public virtual string Id { get; set; } = $"tree-{StringHelper.Guid()}";

        /// <summary>
        /// 实体类型
        /// </summary>
        [Browsable(false), Description("实体类型"), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public virtual Type ModelType
        {
            get => _modelType;
            set
            {
                _modelType = value;
                if (WinFormHelper.IsDesignMode()) return;
                _apiModelInfo = ApiModelManager.Get(ModelType);
                if (_apiModelInfo?.PrimaryKey != null) KeyFieldName = _apiModelInfo.PrimaryKey.Name;
                if (_apiModelInfo?.ParentKey != null) ParentFieldName = _apiModelInfo.ParentKey.Name;
                if (_apiModelInfo?.PathKey != null) PathFieldName = _apiModelInfo.PathKey.Name;
            }
        }

        /// <summary>
        /// 实体元数据
        /// </summary>
        [Browsable(false), Description("实体元数据"),
         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public virtual ApiModel ApiModelInfo => _apiModelInfo;

        /// <summary>
        /// 序号字段名
        /// </summary>
        [Category("XCI"), Description("序号字段名"), DefaultValue("Id")]
        [SmartTagProperty("序号字段名", "XCI", SmartTagActionType.RefreshAfterExecute)]
        public virtual string PathFieldName { get; set; } = "Path";

        /// <summary>
        /// 允许自定义配置
        /// </summary>
        [Category("XCI"), Description("允许自定义配置"), DefaultValue(true)]
        [SmartTagProperty("允许自定义配置", "XCI", SmartTagActionType.RefreshAfterExecute)]
        public bool AllowCustomSetting { get; set; } = true;

        [Category("XCI"), Description("自动加载配置"), DefaultValue(true)]
        [SmartTagProperty("自动加载配置", "XCI", SmartTagActionType.RefreshAfterExecute)]
        public bool AutoLoadSetting { get; set; } = true;

        [Category("XCI"), Description("允许计算序号宽度"), DefaultValue(true)]
        [SmartTagProperty("允许计算序号宽度", "XCI", SmartTagActionType.RefreshAfterExecute)]
        public bool AllowCalcIndicatorWidth { get; set; } = true;

        [Category("XCI"), Description("允许HideSelectionRow应用焦点行样式"), DefaultValue(true)]
        public bool AllowHideSelectionRowApplyFocusedRowStyle { get; set; } = true;

        [Category("XCI"), Description("允许CheckedRowA应用焦点行样式"), DefaultValue(true)]
        public bool AllowCheckedRowApplyFocusedRowStyle { get; set; } = true;

        [Category("XCI"), Description("执行耗时显示BarItem控件"), DefaultValue(null)]
        public BarItem ElapsedTimeItem { get; set; }

        [Category("XCI"), Description("执行耗时显示控件"), DefaultValue(null)]
        public Control ElapsedTimeControl { get; set; }

        /// <summary>
        /// 执行耗时
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public TimeSpan ElapsedTimeSpan { get; private set; }

        /// <summary>
        /// 搜索框
        /// </summary>
        [Category("XCI"), Description("搜索框"), DefaultValue(null),]
        public BaseEdit FilterEdit { get; set; }

        [Category("XCI"), Description("自动生成右键菜单"), DefaultValue(true)]
        [SmartTagProperty("自动生成右键菜单", "XCI", SmartTagActionType.RefreshAfterExecute)]
        public bool AutoPopupMenu { get; set; } = true;

        [Category("XCI"), Description("右键菜单控件"), DefaultValue(null)]
        public PopupMenu PopupMenu { get; set; }

        [Category("XCI"), Description("自动勾选父节点"), DefaultValue(false)]
        public bool AutoCheckedParentNode { get; set; }

        [Category("XCI"), Description("自动勾选子节点"), DefaultValue(false)]
        public bool AutoCheckedChildNode { get; set; }

        [Category("XCI"), Description("是否保留节点焦点状态"), DefaultValue(false)]
        public bool IsReserveNodeFocused { get; set; }

        [Category("XCI"), Description("是否保留节点展开状态"), DefaultValue(false)]
        public bool IsReserveNodeExpandedStatus { get; set; }

        [Category("XCI"), Description("是否保留节点勾选状态"), DefaultValue(false)]
        public bool IsReserveNodeCheckedStatus { get; set; }

        /// <summary>
        /// 是否允许查询面板查询隐藏列
        /// </summary>
        [Category("XCI"), Description("主键字段名"), DefaultValue(false)]
        [XtraSerializableProperty]
        public virtual bool AllowFindHiddenColumn { get; set; }

        [Category("XCI"), Description("是否允许在未加载到数据时显示消息"), DefaultValue(true)]
        [XtraSerializableProperty]
        public virtual bool AllowEmptyDataMessage { get; set; } = true;

        [Category("XCI"), Description("空数据时显示消息"), DefaultValue("暂未查到数据")]
        [XtraSerializableProperty]
        public virtual string EmptyDataMessage { get; set; } = "暂未查到数据";

        private Size? _emptyDataMessageSize;

        [Browsable(false)]
        public Size EmptyDataMessageSize
        {
            get
            {
                if (!_emptyDataMessageSize.HasValue && !string.IsNullOrEmpty(EmptyDataMessage))
                {
                    _emptyDataMessageSize = WinFormHelper.CalcTextSize(EmptyDataMessage);
                }
                return _emptyDataMessageSize ?? Size.Empty;
            }
        }

        [Category("XCI"), Description("空数据时显示消息颜色")]
        [XtraSerializableProperty]
        public virtual Color EmptyDataMessageColor { get; set; } = Color.Gray;

        [Category("XCI"), Description("加载配置之前事件")]
        public event EventHandler<EventArgs> BeforeRestoreLayout;

        [Category("XCI"), Description("加载配置之后事件")]
        public event EventHandler<EventArgs> AfterRestoreLayout;

        [Category("XCI"), Description("获取过滤对象事件")]
        public event EventHandler<DetectTreeFilterObjectEventArgs> DetectFilter;

        [Category("XCI"), Description("数据加载事件")]
        public event EventHandler<LoadTreeDataEventArgs> LoadData;

        [Category("XCI"), Description("数据加载之前事件")]
        public event EventHandler<EventArgs> BeforeLoadData;

        [Category("XCI"), Description("数据加载之后事件")]
        public event EventHandler<EventArgs> AfterLoadData;

        [Category("XCI"), Description("节点复选状态变化事件")]
        public event EventHandler<NodeCheckedChangedEventArgs> NodeCheckedChanged;

        [Category("XCI"), Description("节点拖拽变化事件")]
        public event EventHandler<NodeDragChangedEventArgs> NodeDragChangedChanged;

        [Category("XCI"), Description("行删除事件")]
        public event EventHandler<DeleteDataEventArgs> DeleteData;

        [Category("XCI"), Description("行选择变化事件")]
        public event EventHandler<EventArgs> RowSelectionChanged;

        [Category("XCI"), Description("行双击事件")]
        public event EventHandler<EventArgs> RowDoubleClick;

        [Category("XCI"), Description("控件开始初始化事件")]
        public event EventHandler<EventArgs> BeforeInitialize;
        [Category("XCI"), Description("控件初始化结束事件")]
        public event EventHandler<EventArgs> AfterInitialize;


        protected virtual void OnBeforeInitialize()
        {
            BeforeInitialize?.Invoke(this, EventArgs.Empty);
        }

        protected virtual void OnAfterInitialize()
        {
            AfterInitialize?.Invoke(this, EventArgs.Empty);
        }

        /// <summary>
        /// 获取或者设置表格数据源
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public new object DataSource
        {
            get => base.DataSource;
            set
            {
                if (value == null)
                {
                    base.DataSource = null;
                    return;
                }

                if (IsReserveNodeFocused)
                {
                    if (FocusedNode != null)
                    {
                        _focusNodeId = FocusedNode.GetValue(KeyFieldName);
                    }
                }

                if (IsReserveNodeExpandedStatus)
                {
                    if (_expandNodeIds == null)
                    {
                        _expandNodeIds = new List<object>();
                    }

                    _expandNodeIds.Clear();
                    GetNodeList().FindAll(n => n.Expanded).ForEach(n =>
                    {
                        var idObj = n.GetValue(KeyFieldName);
                        if (idObj != null)
                        {
                            _expandNodeIds.Add(idObj);
                        }
                    });
                }

                if (IsReserveNodeCheckedStatus)
                {
                    if (_checkedNodeIds == null)
                    {
                        _checkedNodeIds = new List<object>();
                    }

                    _checkedNodeIds.Clear();
                    GetNodeList().FindAll(n => n.Checked).ForEach(n =>
                    {
                        var idObj = n.GetValue(KeyFieldName);
                        if (idObj != null)
                        {
                            _checkedNodeIds.Add(idObj);
                        }
                    });
                }

                base.DataSource = value;

                if (IsReserveNodeExpandedStatus)
                {
                    _expandNodeIds.ForEach(id =>
                    {
                        var node = FindNodeByKeyID(id);
                        if (node != null)
                        {
                            node.Expanded = true;
                        }
                    });
                }

                if (IsReserveNodeCheckedStatus)
                {
                    _checkedNodeIds.ForEach(id =>
                    {
                        var node = FindNodeByKeyID(id);
                        if (node != null)
                        {
                            node.Checked = true;
                        }
                    });
                }

                if (IsReserveNodeFocused)
                {
                    if (_focusNodeId != null)
                    {
                        var fnode = FindNodeByKeyID(_focusNodeId);
                        if (fnode != null)
                        {
                            SetFocusedNode(fnode);
                        }
                    }
                }
            }
        }

        protected override async void OnCreateControl()
        {
            base.OnCreateControl();
            if (WinFormHelper.IsDesignMode()) return;

            OnBeforeInitialize();

            //初始化自绘行号事件
            InitDrawRowNumber();

            //初始化数据为空时的消息提示
            InitDrawEmptyDataMessage();

            //初始化行样式
            InitRowStyle();

            //双击表格行
            InitDoubleClick();

            //初始化右键菜单
            InitPopupMenu();

            //初始化复选框勾选事件
            InitCheckNode();

            //初始化节点拖拽
            InitDragNode();

            //初始化表格选中行事件
            InitRowSelectionChanged();

            //初始化表格过滤控件
            InitFilterEdit();

            //初始化表格配置
            InitGridSetting();

            //加载表格配置
            if (AutoLoadSetting)
            {
                await LoadGridSetting();
            }
            OnAfterInitialize();
        }

        public async Task LoadGridSetting()
        {
            SettingManager = new SettingStoreManager(this, Id);

            if (!AutoLoadSetting) return;
            if (!string.IsNullOrEmpty(Id))
            {
                BeforeRestoreLayout?.Invoke(this, EventArgs.Empty);
                await SettingManager.LoadCurrentAsync();
                AfterRestoreLayout?.Invoke(this, EventArgs.Empty);
            }
            else
            {
                Debug.WriteLine("请指定有效的TreeListPlus-Id");
            }
        }

        public void InitGridSetting()
        {
            var allowCustomization = AllowCustomSetting && AppDefaultSettings.AllowCustomTreeControlSetting;
            if (!allowCustomization) return;

            this.PopupMenuShowing += (o, e) =>
            {
                var hitInfo = this.CalcHitInfo(e.Point);
                if (hitInfo.HitInfoType != HitInfoType.Column) return;
                var menu = e.Menu;
                menu.Items.Add(new DXMenuItem("展开节点", (oo, ex) => { this.ExpandAll(); }) { BeginGroup = true });
                menu.Items.Add(new DXMenuItem("合上节点", (oo, ex) => { this.CollapseAll(); }));

                if (OptionsView.ShowCheckBoxes)
                {
                    menu.Items.Add(new DXMenuItem("复选节点", (oo, ex) => { this.CheckAll(); }) { BeginGroup = true });
                    menu.Items.Add(new DXMenuItem("清除复选", (oo, ex) => { this.UncheckAll(); }));
                }

                var customItem = new DXMenuItem("设置", (oo, aa) => ShowSettingForm(), R.GridSettingImage16);
                customItem.BeginGroup = true;
                menu.Items.Add(customItem);
            };
            this.KeyDown += (s, e) =>
            {
                if (e.Control && e.Shift && e.Alt && e.KeyCode == Keys.F12)
                {
                    ShowSettingForm();
                    e.Handled = true;
                }
            };
        }

        /// <summary>
        /// 显示配置窗口
        /// </summary>
        public void ShowSettingForm()
        {
            var settingTreeForm = new FrmSettingTreeForm();
            settingTreeForm.Init(this);
            settingTreeForm.Show();
        }

        protected override List<IDataColumnInfo> GetFindToColumnsCollection()
        {
            if (AllowFindHiddenColumn)
            {
                return base.GetFindToColumnsCollection().Concat(Columns.Where(c => !c.Visible)).ToList();
            }
            return base.GetFindToColumnsCollection();
        }

        #region 计算属性

        /// <summary>
        /// 是否正在加载数据中
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public bool IsDataLoading => isDataLoading;
        /// <summary>
        /// 获取第一个根节点
        /// </summary>
        [Browsable(false),DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public TreeListNode FirstRootNode => Nodes.Count > 0 ? Nodes[0] : null;

        /// <summary>
        /// 选中的主键
        /// </summary>
        [Browsable(false)]
        public string SelectedId => FocusedNode != null ? GetDataId(FocusedNode) : null;

        /// <summary>
        /// 选中的父节点对象主键
        /// </summary>
        [Browsable(false)]
        public string SelectedParentId => FocusedNode != null ? GetDataId(FocusedNode.ParentNode) : null;

        /// <summary>
        /// 获取选中的主键数组
        /// </summary>
        [Browsable(false)]
        public string[] SelectedIdList => GetSelectedIds();

        /// <summary>
        /// 获取选中的主键字符串,用逗号分开
        /// </summary>
        [Browsable(false)]
        public string SelectedIds => GetSelectedIds().JoinString();

        /// <summary>
        /// 获取勾选的主键数组
        /// </summary>
        [Browsable(false)]
        public string[] CheckedIdList => GetCheckedIds();

        /// <summary>
        /// 获取勾选的主键字符串,用逗号分开
        /// </summary>
        [Browsable(false)]
        public string CheckedIds => GetCheckedIds().JoinString();

        /// <summary>
        /// 焦点是否在第一行
        /// </summary>
        [Browsable(false)]
        public bool IsFirstRow => FocusedRowIndex == 0;

        /// <summary>
        /// 焦点是否在最后一行
        /// </summary>
        [Browsable(false)]
        public bool IsLastRow => FocusedRowIndex == RowCount - 1;

        /// <summary>
        /// 是否是当前层级结构中的第一个节点
        /// </summary>
        [Browsable(false)]
        public bool IsLevelFirstNode
        {
            get
            {
                if (FocusedNode != null)
                {
                    return GetNodeIndex(FocusedNode) == 0;
                }
                return false;
            }
        }

        /// <summary>
        /// 是否是当前层级结构中的最后一个节点
        /// </summary>
        [Browsable(false)]
        public bool IsLevelLastNode
        {
            get
            {
                if (FocusedNode != null)
                {
                    var node = FocusedNode;
                    int index = GetNodeIndex(node);
                    int count = node.ParentNode?.Nodes.Count ?? Nodes.Count;
                    if (index == count - 1)
                    {
                        return true;
                    }
                }
                return false;
            }
        }

        /// <summary>
        /// 是否包含数据
        /// </summary>
        [Browsable(false)]
        public bool HasData => Nodes.Count > 0;

        /// <summary>
        /// 是否选中数据
        /// </summary>
        [Browsable(false)]
        public bool HasSelected => FocusedNode != null;

        /// <summary>
        /// 是否选中单条数据
        /// </summary>
        [Browsable(false)]
        public bool HasSingleSelected => Selection.Count == 1;

        /// <summary>
        /// 当前是选中多条
        /// </summary>
        [Browsable(false)]
        public bool HasMultiSelected => Selection.Count > 1;

        /// <summary>
        /// 当前是勾选多条
        /// </summary>
        [Browsable(false)]
        public bool HasMultiChecked => GetAllCheckedNodes().Count > 1;

        /// <summary>
        /// 是否勾选数据
        /// </summary>
        [Browsable(false)]
        public bool HasChecked => GetNodeList().Any(p => p.Checked);

        /// <summary>
        /// 选中的对象
        /// </summary>
        [Browsable(false)]
        public object Selected => FocusedNode != null ? GetObject(FocusedNode) : null;

        /// <summary>
        /// 选中的父节点对象
        /// </summary>
        [Browsable(false)]
        public object SelectedParent => FocusedNode != null ? GetParent(FocusedNode) : null;

        /// <summary>
        /// 获取选中的对象列表
        /// </summary>
        [Browsable(false)]
        public List<object> SelectedList
        {
            get
            {
                var entityList = new List<object>();
                var selectedNodes = Selection;
                int selectedCount = selectedNodes.Count;
                if (selectedCount == 0)
                {
                    return null;
                }
                for (int i = 0; i < selectedCount; i++)
                {
                    entityList.Add(GetObject(selectedNodes[i]));
                }
                return entityList;
            }
        }

        /// <summary>
        /// 获取勾选的对象列表
        /// </summary>
        [Browsable(false)]
        public List<object> CheckedList
        {
            get
            {
                var entityList = new List<object>();
                var selectedNodes = GetAllCheckedNodes();
                int selectedCount = selectedNodes.Count;
                if (selectedCount == 0)
                {
                    return null;
                }
                for (int i = 0; i < selectedCount; i++)
                {
                    entityList.Add(GetObject(selectedNodes[i]));
                }
                return entityList;
            }
        }

        #endregion

        #region 数据方法
        /// <summary>
        /// 根据主键设置节点焦点
        /// </summary>
        /// <param name="id">主键</param>
        public void FocusNodeById(object id)
        {
            var node = FindNodeByKeyID(id);
            if (node != null)
            {
                SetFocusedNode(node);
            }
        }

        /// <summary>
        /// 根据主键查找节点
        /// </summary>
        /// <param name="id">主键</param>
        public TreeListNode FindNodeByDataId(object id)
        {
            return FindNodeByKeyID(KeyFieldName);
        }

        /// <summary>
        /// 获取第一个根节点
        /// </summary>
        public TreeListNode GetFirstRootNode()
        {
            if (Nodes.Count > 0)
            {
                return Nodes[0];
            }
            return null;
        }

        /// <summary>
        /// 获取指定行的对象
        /// </summary>
        /// <param name="node">节点</param>
        public object GetObject(TreeListNode node)
        {
            return GetDataRecordByNode(node);
        }

        /// <summary>
        /// 获取指定行的对象
        /// </summary>
        /// <param name="node">节点</param>
        public object GetParent(TreeListNode node)
        {
            if (node.ParentNode != null)
            {
                return GetObject(node.ParentNode);
            }
            return null;
        }

        /// <summary>
        /// 获取主键
        /// </summary>
        /// <param name="node">节点对象</param>
        public string GetDataId(TreeListNode node)
        {
            return node?.GetValue(KeyFieldName).ToStringOrEmpty();
        }

        /// <summary>
        /// 获取选中的主键数组
        /// </summary>
        public string[] GetSelectedIds()
        {
            var selectedNodes = Selection;
            string[] ids = new string[selectedNodes.Count];
            for (int i = 0; i < selectedNodes.Count; i++)
            {
                ids[i] = GetDataId(selectedNodes[i]);
            }
            return ids;
        }

        /// <summary>
        /// 获取勾选的主键数组
        /// </summary>
        public string[] GetCheckedIds()
        {
            var selectedNodes = GetAllCheckedNodes();
            var ids = new string[selectedNodes.Count];
            for (int i = 0; i < selectedNodes.Count; i++)
            {
                ids[i] = GetDataId(selectedNodes[i]);
            }
            return ids;
        }

        /// <summary>
        /// 设置需要勾选的主键集合
        /// </summary>
        /// <param name="ids">主键集合</param>
        public void SetCheckedNodeIds(Array ids)
        {
            foreach (var item in ids)
            {
                var node = FindNodeByKeyID(item);
                if (node != null)
                {
                    node.Checked = true;
                }
            }
        }

        /// <summary> 
        /// 设置TreeList显示的图标 
        /// </summary> 
        /// <param name="tl">TreeList组件</param> 
        /// <param name="node">当前结点，从根结构递归时此值必须=null</param> 
        /// <param name="nodeIndex">根结点图标(无子结点)</param> 
        /// <param name="parentIndex">有子结点的图标</param> 
        public void SetStateImageIndex(TreeList tl, TreeListNode node, int nodeIndex, int parentIndex)
        {
            if (node == null)
            {
                foreach (TreeListNode N in tl.Nodes)
                    SetStateImageIndex(tl, N, nodeIndex, parentIndex);
            }
            else
            {
                if (node.HasChildren || node.ParentNode == null)
                {
                    //node.SelectImageIndex = parentIndex; 
                    node.StateImageIndex = parentIndex;
                    //node.ImageIndex = parentIndex;
                }
                else
                {
                    //node.SelectImageIndex = nodeIndex; 
                    node.StateImageIndex = nodeIndex;
                    //node.ImageIndex = nodeIndex;
                }

                foreach (TreeListNode N in node.Nodes)
                {
                    SetStateImageIndex(tl, N, nodeIndex, parentIndex);
                }
            }
        }

        /// <summary>
        /// 获取指定节点的父节点的子节点个数(获取指定节点的兄弟节点数量)
        /// </summary>
        /// <param name="node">指定的节点</param>
        protected int GetParentNodeChildNodeCount(TreeListNode node)
        {
            return node.ParentNode?.Nodes.Count ?? Nodes.Count;
        }

        /// <summary>
        /// 展开第一个节点
        /// </summary>
        public void ExpandFirstNode()
        {
            if (Nodes.Count > 0)
            {
                Nodes[0].Expanded = true;
            }
        }

        /// <summary>
        /// 第一个节点设置焦点
        /// </summary>
        public void FocusFirstNode()
        {
            if (Nodes.Count > 0)
            {
                SetFocusedNode(Nodes[0]);
            }
        }

        #endregion

        #region  Init
        /// <summary>
        /// 初始化行样式
        /// </summary>
        private void InitRowStyle()
        {
            if (this.AllowHideSelectionRowApplyFocusedRowStyle)
            {
                ViewInfo.PaintAppearance.HideSelectionRow.ForeColor = ViewInfo.PaintAppearance.FocusedRow.ForeColor;
                ViewInfo.PaintAppearance.HideSelectionRow.BackColor = ViewInfo.PaintAppearance.FocusedRow.BackColor;
            }

            NodeCellStyle += (o, e) =>
            {
                if (this.AllowCheckedRowApplyFocusedRowStyle && e.Node.Checked)
                {
                    e.Appearance.BackColor = ViewInfo.PaintAppearance.FocusedRow.BackColor;
                    e.Appearance.ForeColor = ViewInfo.PaintAppearance.FocusedRow.ForeColor;
                }
            };
        }

        /// <summary>
        /// 初始化自绘行号事件
        /// </summary>
        private void InitDrawRowNumber()
        {
            CustomDrawNodeIndicator += (o, e) =>
            {
                if (!e.IsNodeIndicator) return;
                if (!OptionsView.ShowIndicator) return;
                var args = (IndicatorObjectInfoArgs)e.ObjectArgs;
                var index = this.GetVisibleIndexByNode(e.Node);
                args.DisplayText = index < 0 ? string.Empty : (index + 1).ToString();
                e.ImageIndex = -1;
                CalcIndicatorWidth(this.AllNodesCount);
            };
        }

        private void CalcIndicatorWidth(int maxRecord)
        {
            if (!AllowCalcIndicatorWidth) return;
            var len = maxRecord.ToString().Length;
            if (currentMaxRecordLength == len) return;
            currentMaxRecordLength = len;
            var w = WinFormHelper.GetSingleNumberSize().Width * len;
            if (w < 30) w = 30;
            this.IndicatorWidth = Convert.ToInt32(w);
        }

        /// <summary>
        /// 初始化表格过滤控件
        /// </summary>
        private void InitFilterEdit()
        {
            if (FilterEdit == null) return;
            FilterEdit.KeyDown += (o, e) =>
            {
                if (e.KeyCode == Keys.Up)
                {
                    e.Handled = true;
                    MovePrev();
                }
                else if (e.KeyCode == Keys.Down)
                {
                    e.Handled = true;
                    MoveNext();
                }
                else if (e.KeyData == Keys.Enter)
                {
                    e.Handled = true;
                }
                else if (e.KeyData == Keys.Escape)
                {
                    FilterEdit.Text = string.Empty;
                }
            };
            FilterEdit.KeyPress += (o, e) =>
            {
                if (e.KeyChar == R.EnterKey)
                {
                    if (OptionsBehavior.EnableFiltering == false)
                    {
                        OptionsBehavior.EnableFiltering = true;
                    }
                    ApplyFindFilter(FilterEdit.Text?.Trim());
                    e.Handled = true;
                }
            };
        }

        /// <summary>
        /// 初始化数据为空时的消息提示
        /// </summary>
        private void InitDrawEmptyDataMessage()
        {
            var font = new Font(AppearanceObject.DefaultFont.Name, 16, FontStyle.Regular);
            this.CustomDrawEmptyArea += (o, e) =>
            {
                if (isDataLoading || Nodes.Count > 0) return;
                if (!AllowEmptyDataMessage) return;

                //显示位置
                // Rectangle r = new Rectangle(this.Width / 2 - 100, e.Bounds.Top + 45, e.Bounds.Right - 5, e.Bounds.Height - 5);
                Rectangle r = new Rectangle((this.Width - EmptyDataMessageSize.Width) / 2, e.Bounds.Top + 45, e.Bounds.Right - 5, e.Bounds.Height - 5);
                //显示颜色
                e.Cache.DrawString(EmptyDataMessage, font, e.Cache.GetSolidBrush(EmptyDataMessageColor), r);
                e.Handled = true;
            };
        }

        /// <summary>
        /// 初始化表格行双击事件
        /// </summary>
        private void InitDoubleClick()
        {
            if (RowDoubleClick == null) return;
            DoubleClick += (o, e) =>
            {
                if (e is MouseEventArgs ev)
                {
                    HitInfoType info = CalcHitInfo(ev.Location).HitInfoType;
                    if (ev.Clicks == 2 && ev.Button == MouseButtons.Left &&
                        (info == HitInfoType.ColumnEdge
                         || info == HitInfoType.Button
                         //|| info == HitInfoType.Column
                         || info == HitInfoType.ColumnButton
                         || info == HitInfoType.NodeCheckBox
                         || info == HitInfoType.Empty))
                    {
                        return;
                    }
                }
                FocusedNode.Expanded = true;
                RowDoubleClick?.Invoke(this, EventArgs.Empty);
            };
        }

        /// <summary>
        /// 初始化右键菜单
        /// </summary>
        private void InitPopupMenu()
        {
            var menuManager = MenuManager;
            if (menuManager == null) return;
            if (AutoPopupMenu && PopupMenu == null)
            {
                PopupMenu = new PopupMenu();
                var barManager = (BarManager)menuManager;
                PopupMenu.Manager = barManager;
                foreach (BarItem item in barManager.Items)
                {
                    if (!(item is BarButtonItem)) continue;
                    PopupMenu.ItemLinks.Add(item);
                }
            }

            //注册右键显示事件
            MouseUp += (o, e) =>
            {
                if (PopupMenu == null) return;
                TreeListHitInfo hi = CalcHitInfo(e.Location);
                if (hi.HitInfoType == HitInfoType.Cell && hi.Node != null)
                {
                    FocusedNode = hi.Node;
                }
                if (e.Button == MouseButtons.Right
                    && (hi.HitInfoType == HitInfoType.Cell || hi.HitInfoType == HitInfoType.Empty)
                )
                {
                    PopupMenu.ShowPopup(Control.MousePosition);
                }
            };
        }

        private void OnRowSelectionChanged()
        {
            RowSelectionChanged?.Invoke(this, EventArgs.Empty);
        }

        /// <summary>
        /// 初始化表格选中行事件
        /// </summary>
        private void InitRowSelectionChanged()
        {
            FocusedNodeChanged += (o, e) => OnRowSelectionChanged();
        }

        #endregion

        #region 拖拽节点

        /// <summary>
        /// 初始化节点拖拽
        /// </summary>
        private void InitDragNode()
        {
            BeforeDragNode += (o, e) => dragNode = (TreeListNode)e.Node.Clone();
            AfterDragNode += Tree_AfterDragNode;
        }

        private void Tree_AfterDragNode(object sender, NodeEventArgs e)
        {
            if (string.IsNullOrEmpty(PathFieldName)) return;
            if (e.Node == null || dragNode == null) return;

            string oldParentId = R.RootTreeId;
            string newParentId = R.RootTreeId;
            if (dragNode.ParentNode != null)
            {
                oldParentId = GetDataId(dragNode.ParentNode);
            }
            if (e.Node.ParentNode != null)
            {
                newParentId = GetDataId(e.Node.ParentNode);
            }

            var data = new Dictionary<string, PrimaryKeyValue>();
            if (!oldParentId.Equals(newParentId))//检测拖拽的节点的父节点发送变化了
            {
                //更新老节点顺序
                TreeListNodes oldnodes = dragNode.ParentNode == null ? Nodes : dragNode.ParentNode.Nodes;
                ChangedSortIndex(data, oldnodes);

                //更新新节点顺序
                TreeListNodes newnodes = e.Node.ParentNode == null ? Nodes : e.Node.ParentNode.Nodes;
                ChangedSortIndex(data, newnodes);

                //更新父节点
                AddChangedData(data, new PrimaryKeyValue(GetDataId(e.Node), ParentFieldName, newParentId));
            }
            else //在同级中改变顺序,父节点不变
            {
                TreeListNodes nodes = e.Node.ParentNode == null ? Nodes : e.Node.ParentNode.Nodes;
                ChangedSortIndex(data, nodes);
            }
            NodeDragChangedChanged?.Invoke(this, new NodeDragChangedEventArgs { ChangedData = data.Values.ToList() });
        }

        private void ChangedSortIndex(Dictionary<string, PrimaryKeyValue> data, TreeListNodes nodes)
        {
            foreach (TreeListNode item in nodes)
            {
                AddChangedData(data, new PrimaryKeyValue(GetDataId(item), PathFieldName, GetNodeIndex(item).ToString()));
            }
        }

        /// <summary>
        /// 添加改变的列值
        /// </summary>
        private void AddChangedData(Dictionary<string, PrimaryKeyValue> data, PrimaryKeyValue item)
        {
            if (string.IsNullOrEmpty(item.Id)) return;
            data[item.Id + item.Key] = item;
        }

        #endregion

        #region 复选框

        /// <summary>
        /// 初始化复选框勾选事件
        /// </summary>
        private void InitCheckNode()
        {
            AfterCheckNode += (o, e) =>
            {
                if (AutoCheckedParentNode)
                {
                    CheckedParentNodes(e.Node, p =>
                    {
                        p.Checked = ChildHasCheck(p);
                    });
                }
                if (AutoCheckedChildNode)
                {
                    var nodeChecked = e.Node.Checked;
                    CheckedChildNodes(e.Node, p =>
                    {
                        p.Checked = nodeChecked;
                    });
                }
                SetFocusedNode(e.Node);
                NodeCheckedChanged?.Invoke(this, new NodeCheckedChangedEventArgs { Node = e.Node });
                OnRowSelectionChanged();
            };
        }

        /// <summary>
        /// 递归选中父节点
        /// </summary>
        /// <param name="node"></param>
        /// <param name="action"></param>
        protected void CheckedParentNodes(TreeListNode node, Action<TreeListNode> action)
        {
            RecursionParentNode(node, p =>
            {
                bool b = false;
                for (int i = 0; i < p.Nodes.Count; i++)
                {
                    CheckState state = p.Nodes[i].CheckState;
                    if (!node.CheckState.Equals(state))
                    {
                        b = true;
                        break;
                    }
                }
                p.CheckState = b ? CheckState.Checked : node.CheckState;
                action?.Invoke(p);
            });
        }

        /// <summary>
        /// 递归选中子节点
        /// </summary>
        /// <param name="node"></param>
        /// <param name="action"></param>
        protected void CheckedChildNodes(TreeListNode node, Action<TreeListNode> action)
        {
            RecursionChildNode(node, p =>
            {
                p.CheckState = node.CheckState;
                action?.Invoke(p);
            });
        }

        /// <summary>
        /// 递归父节点
        /// </summary>
        /// <param name="node"></param>
        /// <param name="action"></param>
        public void RecursionParentNode(TreeListNode node, Action<TreeListNode> action)
        {
            if (node.ParentNode == null) return;
            var parentNode = node.ParentNode;
            action(parentNode);
            RecursionParentNode(parentNode, action);
        }

        /// <summary>
        /// 递归子节点
        /// </summary>
        /// <param name="node"></param>
        /// <param name="action"></param>
        public void RecursionChildNode(TreeListNode node, Action<TreeListNode> action)
        {
            if (!node.HasChildren) return;
            for (int i = 0; i < node.Nodes.Count; i++)
            {
                var cnode = node.Nodes[i];
                action(cnode);
                RecursionChildNode(cnode, action);
            }
        }

        /// <summary>
        /// 递归整个树节点
        /// </summary>
        /// <param name="action"></param>
        public void RecursionTreeNode(Action<TreeListNode> action)
        {
            foreach (TreeListNode node in Nodes)
            {
                action(node);
                if (node.HasChildren)
                {
                    RecursionChildNode(node, action);
                }
            }
        }

        /// <summary>
        /// 测试节点的子节点是否有勾选的节点
        /// </summary>
        /// <param name="node">测试节点</param>
        protected bool ChildHasCheck(TreeListNode node)
        {
            foreach (TreeListNode item in node.Nodes)
            {
                if (item.Checked)
                {
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// 获取所有父节点
        /// </summary>
        /// <param name="node">节点</param>
        /// <param name="self">是否包含自身</param>
        public List<TreeListNode> GetAllParentNodes(TreeListNode node, bool self = false)
        {
            var nodes = new List<TreeListNode>();
            RecursionParentNode(node, p => { nodes.Add(p); });
            if (self)
            {
                nodes.Add(node);
            }
            return nodes;
        }

        /// <summary>
        /// 获取所有父节点对象
        /// </summary>
        /// <param name="node">节点</param>
        /// <param name="self">是否包含自身</param>
        public List<object> GetAllParentList(TreeListNode node, bool self = false)
        {
            var list = new List<object>();
            RecursionParentNode(node, p => { list.Add(GetDataRecordByNode(p)); });
            if (self)
            {
                list.Add(GetDataRecordByNode(node));
            }
            return list;
        }

        /// <summary>
        /// 获取所有父节点主键
        /// </summary>
        /// <param name="node">节点</param>
        /// <param name="self">是否包含自身</param>
        public string[] GetAllParentIds(TreeListNode node, bool self = false)
        {
            var nodeids = new List<string>();
            RecursionParentNode(node, p => { nodeids.Add(GetDataId(p)); });
            if (self)
            {
                nodeids.Add(GetDataId(node));
            }
            return nodeids.ToArray();
        }

        /// <summary>
        /// 获取所有子节点
        /// </summary>
        /// <param name="node">节点</param>
        /// <param name="self">是否包含自身</param>
        public List<TreeListNode> GetAllChildNodes(TreeListNode node, bool self = false)
        {
            var nodes = new List<TreeListNode>();
            if (self)
            {
                nodes.Add(node);
            }
            RecursionChildNode(node, p => { nodes.Add(p); });
            return nodes;
        }

        /// <summary>
        /// 获取所有子节点对象
        /// </summary>
        /// <param name="node">节点</param>
        /// <param name="self">是否包含自身</param>
        public List<object> GetAllChildList(TreeListNode node, bool self = false)
        {
            var list = new List<object>();
            if (self)
            {
                list.Add(GetDataRecordByNode(node));
            }
            RecursionChildNode(node, p => { list.Add(GetDataRecordByNode(p)); });
            return list;
        }

        /// <summary>
        /// 获取所有子节点主键
        /// </summary>
        /// <param name="node">节点</param>
        /// <param name="self">是否包含自身</param>
        public string[] GetAllChildIds(TreeListNode node, bool self = false)
        {
            var nodeids = new List<string>();
            if (self)
            {
                nodeids.Add(GetDataId(node));
            }
            RecursionChildNode(node, p => { nodeids.Add(GetDataId(p)); });
            return nodeids.ToArray();
        }

        #endregion

        /// <summary>
        /// 自动生成表格列
        /// </summary>
        public void AutoBuildColumn()
        {
            var modelInfo = ApiModelInfo;
            if (modelInfo == null) return;
            this.OptionsBehavior.Editable = false;
            this.OptionsBehavior.EnableFiltering = false;
            this.OptionsCustomization.AllowSort = false;
            this.OptionsView.ShowFilterPanelMode = ShowFilterPanelMode.Never;
            this.OptionsSelection.EnableAppearanceFocusedCell = false;
            this.OptionsFilter.FilterMode = DevExpress.XtraTreeList.FilterMode.EntireBranch;
            this.OptionsView.ShowCheckBoxes = false;
            this.OptionsView.FocusRectStyle = DrawFocusRectStyle.None;
            this.BorderStyle = BorderStyles.NoBorder;
            this.IndicatorWidth = 30;
            this.RowHeight = 30;
            this.OptionsBehavior.AutoNodeHeight = false;
            this.OptionsBehavior.AutoPopulateColumns = false;
            this.Columns.Clear();

            int index = 0;
            foreach (var item in modelInfo.Propertys)
            {
                var col = item;
                TreeListColumn column = Columns.Add();
                column.VisibleIndex = index + 1;
                column.Name = $"tcol_{item.Name}";
                column.FieldName = col.Name;
                column.Caption = col.Caption ?? col.Name;

                //column.AppearanceCell.Options.UseTextOptions = true;
                //column.AppearanceCell.TextOptions.HAlignment = HorzAlignment.Center;
                //column.AppearanceHeader.Options.UseTextOptions = true;
                //column.AppearanceHeader.TextOptions.HAlignment = HorzAlignment.Center;

                column.OptionsColumn.AllowEdit = false;
                var dataType = col.Property.PropertyType;
                if (dataType == typeof(DateTime) || dataType == typeof(DateTime?))
                {
                    column.Format.FormatType = DevExpress.Utils.FormatType.DateTime;
                    column.Format.FormatString = "yyyy-MM-dd HH:mm:ss";
                }
                else if (dataType == typeof(decimal) || dataType == typeof(decimal?))
                {
                    column.Format.FormatType = DevExpress.Utils.FormatType.Numeric;
                    column.Format.FormatString = "#.##";
                }

                column.Visible = col.Visable;
                if (this.Bands.Count > 0)
                {
                    var band = Bands[0];
                    band.Columns.Add(column);
                }
                index++;
            }
            BestFitColumns();
        }

        public void InvokeRowSelectionChanged()
        {
            OnRowSelectionChanged();
        }

        public void InvokeRowDoubleClick()
        {
            RowDoubleClick?.Invoke(this, EventArgs.Empty);
        }

        protected object OnDetectFilter()
        {
            var args = new DetectTreeFilterObjectEventArgs();
            DetectFilter?.Invoke(this, args);
            return args.Filter;
        }

        /// <summary>
        /// 获取过滤对象
        /// </summary>
        public object GetFilter()
        {
            return OnDetectFilter();
        }

        /// <summary>
        /// 删除Checked数据
        /// </summary>
        public async Task DeleteCheckedAsync(string confirmMessage = null)
        {
            int count = GetAllCheckedNodes().Count;
            await DeleteCoreAsync(count, confirmMessage);
        }

        /// <summary>
        /// 删除选中的数据
        /// </summary>
        public async Task DeleteSelectedAsync(string confirmMessage = null)
        {
            int count = Selection.Count;
            await DeleteCoreAsync(count, confirmMessage);
        }

        /// <summary>
        /// 删除选中的数据
        /// </summary>
        protected async Task DeleteCoreAsync(int count, string confirmMessage = null)
        {
            if (count == 0)
            {
                MessageBoxHelper.ShowError("请选择需要操作的数据");
                return;
            }
            if (string.IsNullOrEmpty(confirmMessage))
            {
                confirmMessage = $"确定要删除选中的 {count} 行数据吗?";
            }
            if (MessageBoxHelper.ShowWarnYesNo(confirmMessage) != DialogResult.Yes)
            {
                return;
            }

            if (DeleteData == null) throw new ArgumentException("请指定删除数据事件");
            var args = new DeleteDataEventArgs();
            DeleteData.Invoke(this, args);
            if (args.Task == null) throw new ArgumentException("请指定删除数据参数Task参数");
            await args.Task.Invoke();
            await LoadAsync();
        }

        public async Task LoadAsync()
        {
            try
            {
                ShowLoadingPanel();
                sw.Reset();
                sw.Start();
                ElapsedTimeSpan = TimeSpan.Zero;
                isDataLoading = true;

                var treeFilter = OnDetectFilter();

                BeforeLoadData?.Invoke(this, EventArgs.Empty);
                if (LoadData == null) return;
                var args = new LoadTreeDataEventArgs { Filter = treeFilter };
                LoadData.Invoke(this, args);
                if (args.Task == null) return;
                var dataSource = await args.Task.Invoke();

                AfterLoadData?.Invoke(this, new AfterLoadTreeDataEventArgs
                {
                    Filter = treeFilter,
                    DataSource = dataSource
                });

                //数据加载成功后
                if (dataSource != null)
                {
                    if (ModelType == null)
                    {
                        if (dataSource is IList list && list.Count > 0)
                        {
                            var firstRow = list[0];
                            this.ModelType = firstRow.GetType();
                        }
                    }
                }

                this.DataSource = dataSource;
            }
            finally
            {
                sw.Stop();
                HideLoadingPanel();
                isDataLoading = false;
                ElapsedTimeSpan = sw.Elapsed;

                if (ElapsedTimeItem != null) ElapsedTimeItem.Caption = $"{sw.Elapsed.TotalMilliseconds:###0.##} ms";
                if (ElapsedTimeControl != null) ElapsedTimeControl.Text = $"{sw.Elapsed.TotalMilliseconds:###0.##} ms";

                OnRowSelectionChanged();
            }
        }

        #region Implementation of ISettingSerializer

        /// <summary>
        /// 保存控件配置
        /// </summary>
        /// <param name="xmlFile">xml文件路径</param>
        public void SaveLayout(string xmlFile)
        {
            FindFilterText = null;
            ClearSorting();
            ActiveFilter.Clear();
            MRUFilters.Clear();
            SaveLayoutToXml(xmlFile, OptionsLayoutBase.FullLayout);
        }

        /// <summary>
        /// 加载配置到控件
        /// </summary>
        /// <param name="xmlFile">xml文件路径</param>
        public void RestoreLayout(string xmlFile)
        {
            Columns.Clear();
            MRUFilters.Clear();
            Appearance.Reset();
            RestoreLayoutFromXml(xmlFile, OptionsLayoutBase.FullLayout);
            ViewInfo.PaintAppearance.HideSelectionRow.BackColor = ViewInfo.PaintAppearance.FocusedRow.BackColor;
        }

        #endregion
    }

    public class LoadTreeDataEventArgs : EventArgs
    {
        /// <summary>
        /// 获取或者设置过滤对象
        /// </summary>
        public object Filter { get; set; }

        public Func<Task<object>> Task { get; set; }
    }


    public class AfterLoadTreeDataEventArgs : EventArgs
    {
        public object Filter { get; set; }

        public object DataSource { get; set; }
    }


    public class DetectTreeFilterObjectEventArgs : EventArgs
    {
        /// <summary>
        /// 获取或者设置过滤对象
        /// </summary>
        public object Filter { get; set; }
    }

    public class NodeCheckedChangedEventArgs : EventArgs
    {
        public TreeListNode Node { get; set; }
    }

    public class NodeDragChangedEventArgs : EventArgs
    {
        public List<PrimaryKeyValue> ChangedData { get; set; }
    }
}